
#ifndef __C_OPENGL_MATERIAL_RENDERER_H_INCLUDED__
#define __C_OPENGL_MATERIAL_RENDERER_H_INCLUDED__

#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_OPENGL_

#ifdef _IRR_WINDOWS_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#endif

#ifdef LINUX
#define GL_GLEXT_LEGACY 1
#include <GL/glx.h>
#include <GL/gl.h>
#include "glext.h"
#endif

#include "COpenGLDriver.h"
#include "IMaterialRenderer.h"

namespace irr
{
    namespace video  
    {

        //! Base class for all internal D3D9 material renderers
        class COpenGLMaterialRenderer : public IMaterialRenderer
        {
        public:

            //! Constructor
            COpenGLMaterialRenderer(video::COpenGLDriver* driver)
                : Driver(driver)
            {
            }

        protected:

            video::COpenGLDriver* Driver;
        };


        //! Solid material renderer
        class COpenGLMaterialRenderer_SOLID : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_SOLID(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);
                        glDisable(GL_TEXTURE_2D);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);
                    }

                    // thanks to Murphy, the following line removed some bugs with several OpenGL
                    // implementations.
                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

                    glDisable(GL_BLEND);
                    glDisable(GL_ALPHA_TEST);
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }
        };


        //! Solid 2 layer material renderer
        class COpenGLMaterialRenderer_SOLID_2_LAYER : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_SOLID_2_LAYER(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services) 
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);
                        glDisable(GL_TEXTURE_2D);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);
                    }

                    glDisable(GL_BLEND);
                    glDisable(GL_ALPHA_TEST);
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }
        };


        //! Transparent add color material renderer
        class COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_TRANSPARENT_ADD_COLOR(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                //if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    glDisable(GL_ALPHA_TEST);

                    Driver->setTexture(1,0);

                    if (Driver->hasMultiTextureExtension())
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                    glEnable(GL_BLEND);
                }

                material.ZWriteEnable = false;
                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            //! Returns if the material is transparent. 
            virtual bool isTransparent() 
            {
                return true; 
            }
        };


        //! Transparent vertex alpha material renderer
        class COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_TRANSPARENT_VERTEX_ALPHA(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    glDisable(GL_ALPHA_TEST);

                    Driver->setTexture(1,0);

                    if (Driver->hasMultiTextureExtension())
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                    glDisable(GL_ALPHA_TEST);

                    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);

                    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT );

                    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PRIMARY_COLOR_EXT );
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE); 

                    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
                    glEnable(GL_BLEND);
                }

                material.ZWriteEnable = false;
                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial()
            {
                // default values
                glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE );
                glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE );
                glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT );
                glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE );
                glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); 

                glDisable(GL_BLEND);
            }

            //! Returns if the material is transparent.
            virtual bool isTransparent()
            {
                return true;
            }
        };


        //! Transparent alpha channel material renderer
        class COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT);

                    glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
                    glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);

                    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                    glEnable(GL_BLEND);

                    glEnable(GL_ALPHA_TEST);

                    f32 refValue = material.MaterialTypeParam;
                    if ( refValue == 0 )
                        refValue = 0.5f;

                    glAlphaFunc(GL_GREATER, refValue);
                }

                //material.ZWriteEnable = false;
                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial() 
            { 
                glDisable(GL_ALPHA_TEST); 
            }

            //! Returns if the material is transparent. 
            virtual bool isTransparent() 
            {
                return true; 
            }
        };



        //! Transparent alpha channel material renderer
        class COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    glEnable(GL_ALPHA_TEST);
                    glDisable(GL_BLEND);

                    glAlphaFunc(GL_GREATER, 0.5);

                    if (Driver->hasMultiTextureExtension()) 
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                    //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
                }

                //material.ZWriteEnable = false;
                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial()
            {
                glDisable(GL_ALPHA_TEST);
            }

            //! Returns if the material is transparent. 
            virtual bool isTransparent() 
            {
                return false;  // this material is not really transparent because it does no blending.
            }
        };


        //! material renderer for all kinds of linghtmaps
        class COpenGLMaterialRenderer_LIGHTMAP : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_LIGHTMAP(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        glDisable(GL_BLEND);
                        glDisable(GL_ALPHA_TEST);

                        // diffuse map

                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE );
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); 

                        // lightmap

                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);

                        glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE );
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE );
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE );

                        if (material.MaterialType == EMT_LIGHTMAP_ADD)
                            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);
                        else
                            glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);

                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);

                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

                        if (material.MaterialType == EMT_LIGHTMAP_M4)
                            glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 4.0f);
                        else
                            if (material.MaterialType == EMT_LIGHTMAP_M2)
                                glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
                            else
                                glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f);
                    }
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }
        };



        //! material renderer for all kinds of linghtmaps
        class COpenGLMaterialRenderer_DETAIL_MAP : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_DETAIL_MAP(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        glDisable(GL_BLEND);
                        glDisable(GL_ALPHA_TEST);

                        // diffuse map

                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);

                        // detailmap

                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD_SIGNED_EXT);

                        glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB_EXT,GL_PREVIOUS_EXT);
                        glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB_EXT,GL_SRC_COLOR);

                        glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB_EXT, GL_TEXTURE);
                        glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB_EXT,GL_SRC_COLOR);
                    }
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }
        };


        //! sphere map material renderer
        class COpenGLMaterialRenderer_SPHERE_MAP : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_SPHERE_MAP(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);
                        glDisable(GL_TEXTURE_2D);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);
                    }

                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

                    glDisable(GL_BLEND);
                    glDisable(GL_ALPHA_TEST);

                    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

                    glEnable(GL_TEXTURE_GEN_S);
                    glEnable(GL_TEXTURE_GEN_T);
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial()
            {
                if (Driver->hasMultiTextureExtension())
                    Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);
                glDisable(GL_TEXTURE_GEN_S);
                glDisable(GL_TEXTURE_GEN_T);
            }
        };


        //! reflection 2 layer material renderer
        class COpenGLMaterialRenderer_REFLECTION_2_LAYER : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_REFLECTION_2_LAYER(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    glDisable(GL_ALPHA_TEST);
                    glDisable(GL_BLEND);

                    if (Driver->hasMultiTextureExtension())
                    {
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE );
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT );

                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);

                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);

                        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                        glEnable(GL_TEXTURE_GEN_S);
                        glEnable(GL_TEXTURE_GEN_T);
                    }
                    else
                    {
                        Driver->setTexture(0,material.Texture1);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                        glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                        glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

                        glEnable(GL_TEXTURE_GEN_S);
                        glEnable(GL_TEXTURE_GEN_T);
                    }
                }

                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial()
            {
                if (Driver->hasMultiTextureExtension())
                {
                    Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // default value
                    Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);

                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                    glDisable(GL_TEXTURE_GEN_S);
                    glDisable(GL_TEXTURE_GEN_T);
                    glDisable(GL_TEXTURE_2D);
                }
                else
                {
                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                    glDisable(GL_TEXTURE_GEN_S);
                    glDisable(GL_TEXTURE_GEN_T);
                }
            }
        };


        //! reflection 2 layer material renderer
        class COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public COpenGLMaterialRenderer
        {
        public:

            COpenGLMaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER(video::COpenGLDriver* d)
                : COpenGLMaterialRenderer(d) {}

            virtual void OnSetMaterial(SMaterial& material, const SMaterial& lastMaterial,
                bool resetAllRenderstates, IMaterialRendererServices* services)
            {
                if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates)
                {
                    if (Driver->hasMultiTextureExtension())
                    {
                        Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE );
                        glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT );

                        Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);

                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);

                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_PREVIOUS_EXT);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_SRC_COLOR);
                        glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
                    }

                    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
                    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
                    glEnable(GL_BLEND);
                    glDisable(GL_ALPHA_TEST);

                    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
                    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

                    glEnable(GL_TEXTURE_GEN_S);
                    glEnable(GL_TEXTURE_GEN_T);
                }

                material.ZWriteEnable = false;
                services->setBasicRenderStates(material, lastMaterial, resetAllRenderstates);
            }

            virtual void OnUnsetMaterial()
            {
                if (Driver->hasMultiTextureExtension())
                {
                    Driver->extGlActiveTextureARB(GL_TEXTURE1_ARB);
                    glDisable(GL_TEXTURE_2D);
                    glDisable(GL_TEXTURE_GEN_S);
                    glDisable(GL_TEXTURE_GEN_T);
                    Driver->extGlActiveTextureARB(GL_TEXTURE0_ARB);
                }	
            }

            //! Returns if the material is transparent.
            virtual bool isTransparent()
            {
                return true;
            }
        };

    } // end namespace video
} // end namespace irr

#endif
#endif

